package subgroup

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"math/big"
	"os"
	"strings"
	"time"
)

// 编码写入文件
func write(filename, Type string, p []byte) error {
	File, err := os.Create(filename)
	defer func(File *os.File) {
		_ = File.Close()
	}(File)
	if err != nil {
		return err
	}
	var b = &pem.Block{Bytes: p, Type: Type}
	return pem.Encode(File, b)
}

// 提取证书信息
func parseCert() *tls.Certificate {
	var cert tls.Certificate
	//获取下一个pem格式证书数据 -----BEGIN CERTIFICATE-----   -----END CERTIFICATE-----
	certDERBlock, err := base64.StdEncoding.DecodeString(JetBraninsCertStr)
	if err != nil {
		return nil
	}
	//附加数字证书到返回
	cert.Certificate = append(cert.Certificate, certDERBlock)

	//解码pem格式的私钥------BEGIN RSA PRIVATE KEY-----   -----END RSA PRIVATE KEY-----
	keyDERBlock, kerr := base64.StdEncoding.DecodeString(JetBraninsPrivateKey)
	if kerr != nil {
		return nil
	}
	var key interface{}
	var errParsePK error
	key, errParsePK = x509.ParsePKCS1PrivateKey(keyDERBlock)

	if errParsePK != nil {
		return nil
	} else {
		cert.PrivateKey = key
	}
	//第一个叶子证书就是我们https中使用的证书
	_, err = x509.ParseCertificate(certDERBlock)
	if err != nil {
		fmt.Println("x509证书解析失败")
		return nil
	}
	return &cert
}

// CreatePower 创建Power插件配置信息
func CreatePower(cert *x509.Certificate, pubKey string) string {
	hashPrefixes := map[crypto.Hash][]byte{
		crypto.MD5:       {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
		crypto.SHA1:      {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14},
		crypto.SHA224:    {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c},
		crypto.SHA256:    {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
		crypto.SHA384:    {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
		crypto.SHA512:    {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
		crypto.MD5SHA1:   {},
		crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14},
	}
	hs := crypto.SHA256
	tem := new(big.Int).SetBytes(cert.Signature)
	s := tem.Text(10)
	m := hs.New()
	m.Write(cert.RawTBSCertificate)
	res := m.Sum(nil)
	pkN := new(big.Int)
	pkN, ok := pkN.SetString(pubKey, 10)
	if !ok {
		panic("failed to parse public key")
	}
	pk := rsa.PublicKey{
		N: pkN,
		E: 65537,
	}
	sjlen := pk.Size()
	hashpflen := len(hashPrefixes[hs])
	reslen := len(res)
	blen := sjlen - reslen - hashpflen - 1
	r := make([]byte, sjlen)
	r[1] = 1
	for i := 2; i < blen; i++ {
		r[i] = 0xff
	}
	copy(r[sjlen-reslen-hashpflen:sjlen-reslen], hashPrefixes[hs])
	copy(r[sjlen-reslen:], res)
	tem.SetBytes(r)
	outStr := "EQUAL," + s + ",65537," + pubKey + "->" + tem.Text(10)
	return outStr
}

// DumpKey 解析KEY
func DumpKey(key string) (string, string, string) {
	shd := map[crypto.Hash]string{
		crypto.MD4:       "3020300c06082a864886f70d020205000410",
		crypto.MD5:       "3020300c06082a864886f70d020505000410",
		crypto.SHA1:      "3021300906052b0e03021a05000414",
		crypto.SHA224:    "302d300d06096086480165030402040500041c",
		crypto.SHA256:    "3031300d060960864801650304020105000420",
		crypto.SHA384:    "3041300d060960864801650304020205000430",
		crypto.SHA512:    "3051300d060960864801650304020305000440",
		crypto.RIPEMD160: "3021300906052b2403020105000414"}
	pz := ""
	pp := strings.Split(key, "-")
	if len(pp) > 3 {
		licensePartBase64 := pp[1]
		ldt, _ := base64.StdEncoding.DecodeString(licensePartBase64)
		signatureBase64 := pp[2]
		sdt, _ := base64.StdEncoding.DecodeString(signatureBase64)
		//fmt.Println(sdt)
		certBase64 := pp[3]
		dt, _ := base64.StdEncoding.DecodeString(certBase64)
		jj, err := x509.ParseCertificate(dt)
		if err != nil {
			return "key err!!!", "", ""
		}
		parsedKey := jj.PublicKey
		xtem, _ := parsedKey.(*rsa.PublicKey)
		isok := false
		hs := ""
		if xtem.Size() > 0 {
			var c, m big.Int
			m.SetBytes(sdt)
			e := big.NewInt(int64(xtem.E))
			c.Exp(&m, e, xtem.N)
			ohex := c.Text(16)
			for r, v := range shd {
				if strings.Contains(ohex, v) {
					m := r.New()
					m.Write(ldt)
					res := hex.EncodeToString(m.Sum(nil))
					if strings.Contains(ohex, res) {
						isok = true
						hs = r.String()
					}
					break
				}
			}
		}
		//h := sha1.New()
		//h.Write(ldt)
		//err = rsa.VerifyPKCS1v15(xtem, crypto.SHA1, h.Sum(nil), sdt)
		rstr := ""
		if isok != true {
			rstr = "KEY签名校验失败！"
		} else {
			rstr = "KEY签名" + hs + "校验通过！"
			//验证是否为正版KEY
			var rr big.Int
			iszb := false
			rr.SetString(RootPublicKey, 10)
			//公钥加密过程
			puk := &rsa.PublicKey{
				N: &rr,
				E: 65537,
			}
			var c, m big.Int
			m.SetBytes(jj.Signature)
			if m.BitLen() < 4000 {
				rstr += " 内置证书签名长度错误!"
				return rstr, string(ldt), pz
			}
			e := big.NewInt(int64(puk.E))
			c.Exp(&m, e, puk.N)

			//私钥解密过程
			/*c.Exp(&m, d, puk.N)*/

			ohex := c.Text(16)
			var ppr crypto.Hash
			for r, v := range shd {
				if strings.Contains(ohex, v) {
					m := r.New()
					m.Write(jj.RawTBSCertificate)
					res := hex.EncodeToString(m.Sum(nil))
					if strings.Contains(ohex, res) {
						iszb = true
						hs = r.String()
						ppr = r
					}
					break
				}
			}

			if iszb {
				rstr += " " + hs + "校验内置证书是正版KEY!"
				m := ppr.New()
				m.Write(jj.RawTBSCertificate)
				res := hex.EncodeToString(m.Sum(nil))
				rstr += "  证书" + ppr.String() + " Code: " + res
			} else {
				rstr += " 非正版KEY!"
				m := sha256.New()
				m.Write(jj.RawTBSCertificate)
				res := hex.EncodeToString(m.Sum(nil))
				rstr += "  证书SHA-256 Code: " + res

				pz = CreatePower(jj, RootPublicKey)
			}
		}

		return rstr, string(ldt), pz
	} else {
		return "key err!!!", "", ""
	}
}

// CreateCrt 创建证书
func CreateCrt(certType int, name string) {
	//生成证书
	type certJson struct {
		CertName             string `json:"certName"`
		LicenseCertStr       string `json:"licenseCertStr"`
		LicensePrivateKey    string `json:"licensePrivateKey"`
		JetBraninsCertStr    string `json:"jetBraninsCertStr"`
		JetBraninsPrivateKey string `json:"jetBraninsPrivateKey"`
	}
	mcertJson := certJson{}
	mcertJson.CertName = name
	if certType == 1 {
		mfile, err := os.ReadFile("cert.json")
		if err == nil {
			_ = json.Unmarshal(mfile, &mcertJson)
			LicenseCertStr = mcertJson.LicenseCertStr
			LicensePrivateKey = mcertJson.LicensePrivateKey
			JetBraninsCertStr = mcertJson.JetBraninsCertStr
			JetBraninsPrivateKey = mcertJson.JetBraninsPrivateKey
			if mcertJson.CertName == name {
				return
			}
		}
	}
	rootKey, err := rsa.GenerateKey(rand.Reader, 4096)
	mp := parseCert()
	if err == nil {
		var buf []byte
		//创建自签名证书
		jj, _ := x509.ParseCertificate(mp.Certificate[0])
		pp := big.Int{}
		kid, _ := pp.SetString("a39eb6486742123641bd6de0b9b4a0528b97f1b3", 16)
		pp.SetString("00d26cb183b28379e1", 16)
		Crt := &x509.Certificate{
			SerialNumber: &pp,
			Subject: pkix.Name{
				CommonName: "JetProfile CA",
			},
			NotBefore:             time.Now(),                                                                 //证书的开始时间
			NotAfter:              time.Now().AddDate(20, 0, 0),                                               //证书的结束时间
			BasicConstraintsValid: true,                                                                       //基本的有效性约束
			IsCA:                  true,                                                                       //是否是根证书
			ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, //证书用途
			KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
			SubjectKeyId:          kid.Bytes(),
		}

		Crt.ExtraExtensions = jj.Extensions //复制源证书的扩展信息

		//err = write("jjy.crt", "CERTIFICATE", jj.Raw) //备份源证书
		buf, err = x509.CreateCertificate(rand.Reader, Crt, Crt, &rootKey.PublicKey, rootKey) //创建jetbrains根证书
		if certType == 0 {
			_ = write("rootCert.crt", "CERTIFICATE", buf)
		}
		ppk, _ := x509.ParseCertificate(buf)

		Crt.Subject.CommonName = "License Servers CA"
		pp = big.Int{}
		pp.SetString("00c0ab5bd1d5fa18d9", 16)
		Crt.SerialNumber = &pp
		ee := big.Int{}
		ee.SetString("a6c462133faebe1e93b10aaeaedc1731de09f151", 16)
		Crt.SubjectKeyId = ee.Bytes()
		buf, err = x509.CreateCertificate(rand.Reader, Crt, Crt, &rootKey.PublicKey, rootKey) //创建License根证书
		ppk2, _ := x509.ParseCertificate(buf)

		buf = x509.MarshalPKCS1PrivateKey(rootKey)
		if certType == 0 {
			_ = write("rootPrivateKey.key", "PRIVATE KEY", buf)
		}
		Crt.IsCA = false
		Crt.Subject.CommonName = name
		Crt.NotBefore = time.Now()
		Crt.NotAfter = time.Now().AddDate(80, 0, 0)
		Crt.SerialNumber, _ = pp.SetString("0d", 16)
		Crt.ExtKeyUsage = jj.ExtKeyUsage
		Crt.KeyUsage = jj.KeyUsage
		Crt.SubjectKeyId = jj.SubjectKeyId

		Keym, _ := rsa.GenerateKey(rand.Reader, 2048)
		buf, err = x509.CreateCertificate(rand.Reader, Crt, ppk, &Keym.PublicKey, rootKey) //创建子证书用根证书签名
		if certType == 1 {
			JetBraninsCertStr = base64.StdEncoding.EncodeToString(buf)
			mcertJson.JetBraninsCertStr = JetBraninsCertStr
		} else {
			_ = write("JetBraninsCert.crt", "CERTIFICATE", buf)
		}
		//生成licenseCert
		initialCert := "MIIEVDCCAjygAwIBAgIBBzANBgkqhkiG9w0BAQsFADAdMRswGQYDVQQDDBJMaWNlbnN" +
			"lIFNlcnZlcnMgQ0EwHhcNMTgwMzI3MTIwNDE4WhcNMjgwMzIzMTIwNDE4WjAvMS0wKwYDVQQDEyRsc" +
			"3J2LXByb2QtdGlsbC0yMDI4MDMyNi1pbnRlcm1lZGlhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwA" +
			"wggEKAoIBAQCmxBo4iYtqlYluqPUVv2OA8+dBV31BGmSSiUV9dotvGV0DSYqSuhCCsvZPyly7nZ6dk" +
			"3ccThzBG398uveTV2YamzCBfQIaZ5BxzmWJcrq8i8Ddb+OGXGnoIxXTeRS6A5Vj3TmT7nP4AyrHzAU" +
			"RVgh5NxVA04hDce43+q43kKfvNzIIKwuKlRMKhrfPhvpd83XIbZ09gUyW4edrLdBSCTvw78/hlUor0" +
			"yVd9YJMnHxVngGkKKBWENAYz9EcuZc+pzf97oWKO+w2KB8NsFCGA3nyqT3l3FqXQ6o0rC1otPH93Vf" +
			"GqOrLlz3C8QoiSR4OR6U8cF5nWlxP4WyNHqAxq81BAgMBAAGjgYwwgYkwDAYDVR0TBAUwAwEB/zAdB" +
			"gNVHQ4EFgQU5nQdbTaCH11+6HS60Nif5AQNNqEwTQYDVR0jBEYwRIAUpsRiEz+uvh6TsQqurtwXMd4" +
			"J8VGhIaQfMB0xGzAZBgNVBAMMEkxpY2Vuc2UgU2VydmVycyBDQYIJAMCrW9HV+hjZMAsGA1UdDwQEA" +
			"wIBBjANBgkqhkiG9w0BAQsFAAOCAgEAh65DnHqIMlVaakVCg0hpxVMt1GWsdqKoNB29+D32g55zcxO" +
			"ycDogmgi0MLt94mPEbS5cTy0Izj5Tgq281lqdMgxg7jVuS8VQip1ylcBrs1bachqIJrpcrf/EpmlFs" +
			"UV/0D1Ss0TNqPFT72ZC+LCXSH+4nXUQthr9GpT16Rz6ly+aZsXQszGWhvptBfXS+rLGgEJE43QIYcY" +
			"JLfTE+WMzOSLLAjcM+vnI3cmvmt7fBkg3p2kYOAa2e/zyHgp0aNt8f31OeO9yfID/wVCv9iMLggCny" +
			"dGG1DBigksEE+JBlSAT2r6lGX2kAcrt+yo1xf8PvfqcJur8lSruO7GQuXLbOhE6ZIh6Hhxg7uMCbv+" +
			"r/xvKtThvC4WKqos1sTdHiT0mB7tVKQCkLh+zIf8w2LOKrj/8hge4qePrSOQ9wh+tRm4XyKx8sJea0" +
			"l/B7CKM/d1X0tM5hpgKSWUAp4zPrbcajag5HDTPfkFgDAYQBH+eKnPT/S6jznYcouYAvGZbVYK0yZR" +
			"eu0d+5Y79Dq7Nw9Ie6rc82KEKTA586+0BYDSrkyEfrICYM1fnU5jEZCK08shf1snHb3/LftQOPjmrY" +
			"JL/oedEuArLnEFLASzi6DcQit9oma2YWPw5CvgEomOoX+4GleJjGp5qc8jHSCecn9h9gu2Qzs+Wr44" +
			"q+tLgvgCA+d0=\n"
		lkey, _ := base64.StdEncoding.DecodeString(initialCert)
		mm, _ := x509.ParseCertificate(lkey)
		mm.PublicKey = nil
		Crt.IsCA = true
		Crt.Subject.CommonName = name + ".lsrv.jetbrains.com"
		Crt.NotBefore = time.Now()
		Crt.NotAfter = time.Now().AddDate(80, 0, 0)
		Crt.SerialNumber = mm.SerialNumber
		Crt.ExtKeyUsage = mm.ExtKeyUsage
		Crt.KeyUsage = mm.KeyUsage
		Crt.SubjectKeyId = mm.SubjectKeyId
		Crt.ExtraExtensions = mm.Extensions //复制源证书的扩展信息
		lKeym, _ := rsa.GenerateKey(rand.Reader, 2048)
		buf, err = x509.CreateCertificate(rand.Reader, Crt, ppk2, &lKeym.PublicKey, rootKey) //创建子证书用根证书签名
		if certType == 1 {
			LicenseCertStr = base64.StdEncoding.EncodeToString(buf)
			mcertJson.LicenseCertStr = LicenseCertStr
		} else {
			_ = write("licenseCert.crt", "CERTIFICATE", buf)
		}
		buf = x509.MarshalPKCS1PrivateKey(lKeym)
		if certType == 1 {
			LicensePrivateKey = base64.StdEncoding.EncodeToString(buf)
			mcertJson.LicensePrivateKey = LicensePrivateKey
		} else {
			_ = write("licensePrivateKey.key", "PRIVATE KEY", buf)
		}

		buf = x509.MarshalPKCS1PrivateKey(Keym)

		if certType == 1 {
			JetBraninsPrivateKey = base64.StdEncoding.EncodeToString(buf)
			mcertJson.JetBraninsPrivateKey = JetBraninsPrivateKey
		} else {
			_ = write("JetBraninsPrivateKey.key", "PRIVATE KEY", buf)
		}
		if certType != 1 {
			fmt.Println("证书已保存到当前目录下！")
			var stop string
			_, _ = fmt.Scanln(&stop)
		} else {
			certJsonStr, _ := json.Marshal(&mcertJson)
			_ = os.WriteFile("cert.json", certJsonStr, 0666)
		}
	}
}

// CreateKey 生成注册KEY
func CreateKey(licenseId *string, licenseeName *string, metaData *string, hash *string, fallbackDate *string, rcode *string) string {
	mp := parseCert()
	mpk, _ := x509.ParseCertificate(mp.Certificate[0])
	mkk, _ := mp.PrivateKey.(*rsa.PrivateKey)

	var ls = License{LicenseId: *licenseId, LicenseeName: *licenseeName, AssigneeName: "", AssigneeEmail: "",
		CheckConcurrentUse: false, Metadata: *metaData, Hash: *hash, GracePeriodDays: 7,
		AutoProlongated: false, IsAutoProlongated: false,
	}

	products := []MCode{
		{Code: "PSI", Extended: true},
		{Code: "PCWMP", Extended: true},
		{Code: "PSW", Extended: true},
		{Code: "PWS", Extended: true},
		{Code: "RSV", Extended: true},
		{Code: "RSC", Extended: true},
		{Code: "RSF", Extended: true},
		{Code: "RS", Extended: true},
		{Code: "PRB", Extended: true},
		{Code: "PPC", Extended: true},
		{Code: "PGO", Extended: true},
		{Code: "PPS", Extended: true},
		{Code: "PDB", Extended: true},
		{Code: "DP", Extended: true},
		{Code: "DPN", Extended: true},
		{Code: "RC", Extended: true},
		{Code: "DC", Extended: true},
		{Code: "PELASTICSEARCH", Extended: true},
		{Code: "PBASHSUPPORTPRO", Extended: true},
		{Code: "RS0", Extended: true},
		{Code: "DM", Extended: true},
	}

	if *rcode == "all" {
		products = append(products, []MCode{
			{Code: "II"}, //IntelliJ IDEA
			{Code: "AC"}, //AppCode
			{Code: "WS"}, //WebStorm
			{Code: "PS"}, //PhpStorm
			{Code: "RM"}, //RubyMine
			{Code: "CL"}, //Clion
			{Code: "PC"}, //PyCharm
			{Code: "DB"}, //DataGrip
			{Code: "GO"}, //GoLand
			{Code: "RD"}, //RiDer
			{Code: "DS"}, //DataSpell
			{Code: "RR"}, //RustRover
			{Code: "PMYBATISHELPER"},
			{Code: "PCMAKEPLUS"},
			{Code: "PEXTRAICONS"},
			{Code: "RSU"}, //ReSharper C++  ?
		}...)
	} else {
		products = append(products, MCode{Code: *rcode})
	}

	for i := range products {
		products[i].PaidUpTo = *fallbackDate
		products[i].FallbackDate = *fallbackDate
	}

	ls.Products = products

	outLicenseId := ls.LicenseId
	jmldt, _ := json.Marshal(&ls)
	//fmt.Println(string(bls), "\r\n")
	hf := sha1.New()
	hf.Write(jmldt)
	hashed := hf.Sum(nil)
	sdtp, err := rsa.SignPKCS1v15(rand.Reader, mkk, crypto.SHA1, hashed)
	if err != nil {
		fmt.Println(err.Error())
	}
	outLicense := base64.StdEncoding.EncodeToString(jmldt)
	outSi := base64.StdEncoding.EncodeToString(sdtp)
	outCer := base64.StdEncoding.EncodeToString(mpk.Raw)
	return outLicenseId + "-" + outLicense + "-" + outSi + "-" + outCer
}
